package com.fmy.jurisdiction.modular.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fmy.jurisdiction.core.commons.consts.SystemConsts;
import com.fmy.jurisdiction.core.commons.kits.BizExceptionKit;
import com.fmy.jurisdiction.core.commons.kits.MybatisPlusKit;
import com.fmy.jurisdiction.modular.model.AdminRole;
import com.fmy.jurisdiction.modular.mapper.AdminRoleMapper;
import com.fmy.jurisdiction.modular.model.AdminRolePerm;
import com.fmy.jurisdiction.modular.model.AdminUser;
import com.fmy.jurisdiction.modular.model.vo.AdminRoleChildren;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fmy.jurisdiction.modular.service.IAdminPermissionService;
import com.fmy.jurisdiction.modular.service.IAdminRolePermService;
import com.fmy.jurisdiction.modular.service.IAdminRoleService;
import com.fmy.jurisdiction.modular.service.IAdminUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 角色表 服务实现类
 * </p>
 *
 * @author Mr.fmy
 * @since 2019-09-16
 */
@Service
public class AdminRoleServiceImpl extends ServiceImpl<AdminRoleMapper, AdminRole> implements IAdminRoleService {

    @Autowired
    private AdminRoleMapper thisMapper;
    @Autowired
    private IAdminUserService userService;
    @Autowired
    private IAdminRolePermService rolePermService;
    @Autowired
    private IAdminPermissionService permissionService;

    @Override
    public boolean addAdminRole() {
        AdminRole role = new AdminRole();
        role.setId(SystemConsts.ROLE_ADMIN_ID)
                .setRoleName("超级管理员")
                .setCode("admin")
                .setFCode(SystemConsts.ROLE_TOP)
                .setFCodes(SystemConsts.ROLE_TOP)
                .setCreateTime(LocalDateTime.now()).setCreateUser(SystemConsts.USER_ADMIN_ID);
        return thisMapper.addAdminRole(role) > 0;
    }

    @Override
    public int getIdCount(Integer id) {
        return this.count(MybatisPlusKit.<AdminRole>q().eq(AdminRole.ID, id));
    }

    @Override
    public int getMaxLevel(String roles) {
        if (StrUtil.isEmpty(roles)) return -1;
        return this.getObj(MybatisPlusKit.<AdminRole>q()
                .select(StrUtil.format("max({})", AdminRole.LEVEL))
                .in(AdminRole.ID, Convert.toList(roles)), item -> {
            return NumberUtil.parseInt(item.toString());
        });
    }

    @Override
    public boolean addRole(AdminRole role) {
        BizExceptionKit.throwBusiness(this.count(MybatisPlusKit.<AdminRole>q().eq(AdminRole.CODE, role.getCode())) > 0, "角色Code已存在");
        //查询父角色
        AdminRole fRole = this.getOne(MybatisPlusKit.<AdminRole>q().eq(AdminRole.CODE, role.getFCode()));
        BizExceptionKit.throwBusiness(fRole == null, "父角色不存在");
        //填充信息
        role.setCreateTime(LocalDateTime.now())
                .setLevel(fRole.getLevel() + 1)
                .setFCodes(fRole.getFCodes() + SystemConsts.ROLE_PERMI_SEPARATOR + fRole.getCode());
        return this.save(role);
    }

    @Override
    public boolean modifyRole(Integer rid, String roleName, Integer optionUser) {
        return this.update(MybatisPlusKit.<AdminRole>u()
                .eq(AdminRole.ID, rid)
                .set(AdminRole.ROLE_NAME, roleName)
                .set(AdminRole.MODIFY_TIME, LocalDateTime.now())
                .set(AdminRole.MODIFY_USER, optionUser));
    }

    @Override
    public boolean delRole(Integer rid) {
        BizExceptionKit.throwBusiness(rid == SystemConsts.ROLE_ADMIN_ID, "该角色不可操作");
        Integer count = userService.count(MybatisPlusKit.<AdminUser>q().like(AdminUser.ROLES, rid));
        BizExceptionKit.throwBusiness(count > 0, "该角色存在关联用户、不可删除");
        BizExceptionKit.throwBusiness(rolePermService.count(MybatisPlusKit.<AdminRolePerm>q().eq(AdminRolePerm.ROLE_ID, rid)) > 0, "该角色存在对应权限、不可删除");
        return this.removeById(rid);
    }

    @Override
    public boolean allocationPrem(Integer rid, Integer premId, boolean type) {
        //效验是否可以分配该权限
        String pcode = permissionService.findByIdToPcode(premId);
        BizExceptionKit.throwBusiness(StrUtil.isEmpty(pcode), "未找到该权限");
        if (!SystemConsts.PERMISSION_TOP.equals(pcode)) {
            //效验该角色是否关联该父权限
            Integer pid = permissionService.findByCodeToId(pcode);
            BizExceptionKit.throwBusiness(rolePermService.findByRolePermId(rid, pid) == 0, "无法分配权限、因该角色未拥有分配权限的父权限关系");
        }
        //不限制那么严格
        if (type) {
            BizExceptionKit.throwBusiness(this.getIdCount(rid) == 0, "角色不存在");
            if (rolePermService.findByRolePermId(rid, premId) == 0) {
                rolePermService.save(new AdminRolePerm(rid, premId));
            }
        } else {
            rolePermService.remove(MybatisPlusKit.<AdminRolePerm>q().eq(AdminRolePerm.ROLE_ID, rid).eq(AdminRolePerm.PERMISSION_ID, premId));
        }
        return true;
    }

    @Override
    public List<AdminRoleChildren> getRoleChildren(Integer roleId) {
        QueryWrapper<AdminRole> q = MybatisPlusKit.<AdminRole>q();
        q.like(roleId != null, AdminRole.F_CODES, roleId)
                .or().eq(roleId != null, AdminRole.ID, roleId);
        List<AdminRole> roles = this.list(q);
        List<AdminRoleChildren> roleChildren = new ArrayList<>();
        int topLevel = roles.size() > 1 ? roles.stream().mapToInt(item -> item.getLevel()).min().getAsInt() : roles.get(0).getLevel();
        roles.forEach(item -> {
            if (item.getLevel().equals(topLevel)) {
                AdminRoleChildren children = new AdminRoleChildren();
                BeanUtils.copyProperties(item, children);
                roleChildren.add(children);
            }
        });
        //递归
        roleChildren.forEach(item -> {
            item.setChildren(recursion(item, roles));
        });
        return roleChildren;
    }

    private List<AdminRoleChildren> recursion(AdminRoleChildren children, List<AdminRole> roles) {
        List<AdminRoleChildren> childrens = new ArrayList<>();
        roles.forEach(item -> {
            if (children.getCode().equals(item.getFCode())) {
                AdminRoleChildren childrenItem = new AdminRoleChildren();
                BeanUtils.copyProperties(item, childrenItem);
                childrens.add(childrenItem);
            }
        });
        //再次递归
        childrens.forEach(item -> {
            item.setChildren(recursion(item, roles));
        });
        return childrens.size() > 0 ? childrens : null;
    }
}
